﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Text.RegularExpressions;
using System.Web.UI;
using BrandonHaynes.Membership.Factors.PromptControls;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Users;
using DotNetNuke.Security.Membership;
using DotNetNuke.Services.Log.EventLog;
using DotNetNuke.Services.Mail;
using System;

namespace BrandonHaynes.Membership.Factors
	{
	/// <summary>
	/// A class that sends (and requires) a one-time password sent to a user via the Clickatell SMS gateway service.
	/// 
	/// Note that this class may be extended to support most any SMS service gateway.
	/// </summary>
	public class SmsFactor : AbstractSmsFactor
		{
		public SmsFactor(IDictionary<string, string> attributes)
			: base(attributes)
			{ }

		#region IAuthenticationFactor Members

		public override string Name { get { return "ClickatellSMS"; } }

		#endregion

		/// <summary>
		/// Transmits a one-time password to a user via the SMS gateway service
		/// </summary>
		/// <param name="user">The user attempting to authenticate</param>
		/// <param name="telephone">The destination telephone number for the SMS message</param>
		/// <param name="onetimePassword">The one-time password to be used for subsequent authentication</param>
		protected override void SendSms(UserInfo user, string telephone, string onetimePassword)
			{
			// Load up our configuration values from the attribute dictionary
			var sourceAddress = Attributes.GetValueOrDefault("source", "One-time Password");
			var apiId = int.Parse(Attributes["appId"], CultureInfo.InvariantCulture);
			var smsUser = Attributes["userName"];
			var smsPassword = Attributes["password"];
			var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); // HTTPS is required
			var endpoint = new EndpointAddress(Attributes.GetValueOrDefault("endPoint", "https://api.clickatell.com:443/soap/webservice.php"));

			// Execute the secure webservice call and transmit the one-time password to the destination address
			var results = new SMS.ClickATell.PushServerWSPortTypeClient(binding, endpoint).sendmsg(string.Empty, apiId, smsUser, smsPassword, new string[] { telephone }, sourceAddress, onetimePassword, 0, 1, 0, 0, 3, 0, 1, 1, 0, string.Empty, 0, "SMS_TEXT", string.Empty, string.Empty, 1440);

			// The Clickatell SMS gateway returns error messages of the form /^ERR:.*/.  Match and log, if any.
			if (results.Any(result => result.StartsWith("ERR", StringComparison.OrdinalIgnoreCase)))
				new EventLogController().AddLog("SMS", string.Format(CultureInfo.InvariantCulture, "{0} / {1}", string.Join(" / ", results), telephone), PortalController.GetCurrentPortalSettings(), user.UserID, EventLogController.EventLogType.PASSWORD_SENT_FAILURE);
			}
		}
	}
